# -*- coding: utf-8 -*-
from django import forms
from django.db.models import Q
from django.contrib.auth.models import User, Group
from django.shortcuts import get_object_or_404
from django.contrib.auth.models import User
from django.forms import models
from django.forms.widgets import RadioSelect, CheckboxInput, Select
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.contrib.auth.forms import UserCreationForm
from skoolmaster.general.models import Post, Region, Country, Faculty, UserProfile, Enrollment,\
  EnrollmentSubject
from skoolmaster.syllabus.models import Subject, UniversityProgram, FacultyModule, FacultyYear, SchoolYear, StudentSubjectMetadata
from skoolmaster.general.fields import EMSOField
from skoolmaster.general.widgets import HorizontalFilterWidget
from skoolmaster.exams.models import ExamApplication
import skoolmaster.general.search as search

class PostForm(forms.Form):
  """
  Custom Post form.
  """
  model = Post
  def __init__(self, *args, **kwargs):
    self.edit = kwargs.pop('edit', False)
    instance = kwargs.pop('instance', None)
    super(PostForm, self).__init__(*args, **kwargs)
    self.fields['postal_num'] = forms.RegexField(regex = '^[0-9a-zA-Z]{4}$', label = u"Poštna številka", initial = instance.postal_num if instance else None, error_messages = { 'invalid' : u"Poštna številka mora biti sestavljena iz 4 števk." })
    self.fields['post_office'] = forms.CharField(label = u"Pošta", initial = instance.post_office if instance else None)
    self.fields['disabled'] = forms.BooleanField(label = u"Šifra ni več veljavna", initial = instance.disabled if instance else None, required = False)
    
    if self.edit:
      self.fields['postal_num'].widget.attrs.update({'readonly' : 'readonly'})    

  def clean_postal_num(self):
    postal_num = self.cleaned_data['postal_num'].upper()
    try:
        Post.objects.get(postal_num = postal_num)
    except:
        return postal_num
    if not self.edit:
      raise forms.ValidationError('Pošta s to številko že obstaja!')
    else:
      return postal_num

  def save(self):
    Post(
      postal_num = self.cleaned_data['postal_num'],
      post_office = self.cleaned_data['post_office'].upper(),
      disabled = self.cleaned_data['disabled']
    ).save()

  @staticmethod
  def search_logic(query, queryset):
    return search.post_search_logic(query, queryset)
  
class RegionForm(forms.Form):
  """
  Custom Region form.
  """
  model = Region
  def __init__(self, *args, **kwargs):
    self.edit = kwargs.pop('edit', False)
    instance = kwargs.pop('instance', None)
    super(RegionForm, self).__init__(*args, **kwargs)
    self.fields['id'] = forms.RegexField(regex = '^[0-9a-zA-Z]{3}$', label = u"Šifra", initial = instance.id if instance else None, error_messages = { 'invalid' : u"Šifra občine mora biti sestavljena iz 3 števk." })
    self.fields['name'] = forms.CharField(label = u"Občina", initial = instance.name if instance else None)
    self.fields['disabled'] = forms.BooleanField(label = u"Šifra ni več veljavna", initial = instance.disabled if instance else None, required = False)
    
    if self.edit:
      self.fields['id'].widget.attrs.update({'readonly' : 'readonly'})    

  def clean_id(self):
    id = self.cleaned_data['id'].upper()
    try:
        Region.objects.get(id = id)
    except:
        return id
    if not self.edit:
      raise forms.ValidationError('Občina s to šifro že obstaja!')
    else:
      return id

  def save(self):
    Region(
      id = self.cleaned_data['id'].upper(),
      name = self.cleaned_data['name'].upper(),
      disabled = self.cleaned_data['disabled']
    ).save()

  @staticmethod
  def search_logic(query, queryset):
    return search.id_or_name_search_logic(query, queryset)
  
class CountryForm(forms.Form):
  """
  Custom Country form.
  """
  model = Country
  def __init__(self, *args, **kwargs):
    self.edit = kwargs.pop('edit', False)
    instance = kwargs.pop('instance', None)
    super(CountryForm, self).__init__(*args, **kwargs)
    self.fields['id'] = forms.RegexField(regex = '^[0-9a-zA-Z]{3}$', label = u"Šifra", initial = instance.id if instance else None, error_messages = { 'invalid' : u"Šifra države mora biti sestavljena iz 3 števk." })
    self.fields['name'] = forms.CharField(label = u"Država", initial = instance.name if instance else None)
    self.fields['disabled'] = forms.BooleanField(label = u"Šifra ni več veljavna", initial = instance.disabled if instance else None, required = False)
    
    if self.edit:
      self.fields['id'].widget.attrs.update({'readonly' : 'readonly'})    

  def clean_id(self):
    id = self.cleaned_data['id'].upper()
    try:
        Country.objects.get(id = id)
    except:
        return id
    if not self.edit:
      raise forms.ValidationError('Država s to šifro že obstaja!')
    else:
      return id

  def save(self):
    Country(
      id = self.cleaned_data['id'].upper(),
      name = self.cleaned_data['name'].upper(),
      disabled = self.cleaned_data['disabled']
    ).save()

  @staticmethod
  def search_logic(query, queryset):
    return search.id_or_name_search_logic(query, queryset)  
  
class FacultyForm(forms.Form):
  """
  Custom Faculty form.
  """
  model = Faculty
  def __init__(self, *args, **kwargs):
    self.edit = kwargs.pop('edit', False)
    instance = kwargs.pop('instance', None)
    super(FacultyForm, self).__init__(*args, **kwargs)
    self.fields['id'] = forms.RegexField(regex = '^[0-9a-zA-Z]{3}$', label = u"Šifra", initial = instance.id if instance else None, error_messages = { 'invalid' : u"Šifra fakultete mora biti sestavljena iz 3 števk." })
    self.fields['name'] = forms.CharField(label = u"Fakulteta", initial = instance.name if instance else None)
    self.fields['disabled'] = forms.BooleanField(label = u"Šifra ni več veljavna", initial = instance.disabled if instance else None, required = False)
    
    if self.edit:
      self.fields['id'].widget.attrs.update({'readonly' : 'readonly'})    

  def clean_id(self):
    id = self.cleaned_data['id'].upper()
    try:
        Faculty.objects.get(id = id)
    except:
        return id
    if not self.edit:
      raise forms.ValidationError('Fakulteta s to šifro že obstaja!')
    else:
      return id

  def save(self):
    Faculty(
      id = self.cleaned_data['id'].upper(),
      name = self.cleaned_data['name'].upper(),
      disabled = self.cleaned_data['disabled']
    ).save()

  @staticmethod
  def search_logic(query, queryset):
    return search.id_or_name_search_logic(query, queryset)

class LecturerUserForm(forms.Form):
  """
  Custom Lecturer form.
  """
  model = UserProfile
  def __init__(self, *args, **kwargs):
    self.edit = kwargs.pop('edit', False)
    instance = kwargs.pop('instance', None)
    super(LecturerUserForm, self).__init__(*args, **kwargs)
    self.fields['sifra'] = forms.RegexField(regex = '^[0-9a-zA-Z]{6}$', label = u"Šifra", initial = instance.sifra if instance else None, error_messages = { 'invalid' : u"Šifra predavatelja mora biti sestavljena iz 6 števk." })
    self.fields['name'] = forms.CharField(label = u"Ime", initial = instance.name if instance else None)
    self.fields['surname'] = forms.CharField(label = u"Priimek", initial = instance.surname if instance else None)
    self.fields['disabled'] = forms.BooleanField(label = u"Šifra ni več veljavna", initial = instance.disabled if instance else None, required = False)
    
    if self.edit:
      self.fields['username'] = forms.CharField(initial = instance.user.username, label = 'Uporabniško ime')
      self.fields['username'].widget.attrs.update({'readonly' : 'readonly'})
      self.fields['sifra'].widget.attrs.update({'readonly' : 'readonly'})
    else:
      self.fields['username'] = forms.RegexField(label = "Uporabniško ime", max_length=30, regex=r'^\w+$', error_message = "Uporabniško ime je lahko sestavljeno le iz črk, števil in podčrtajev.")
      self.fields['pass'] = forms.CharField(label = "Geslo", widget = forms.PasswordInput)
      self.fields['pass2'] = forms.CharField(label = "Ponovite geslo", widget = forms.PasswordInput)
  
  def clean_sifra(self):
    sifra = self.cleaned_data['sifra'].upper()
    try:
        UserProfile.objects.get(sifra = sifra)
    except:
        return sifra
      
    if not self.edit:
      raise forms.ValidationError('Predavatelj s to šifro že obstaja!')
    else:
      return sifra
  
  def clean_username(self):
    username = self.cleaned_data["username"]
    try:
        User.objects.get(username = username)
    except User.DoesNotExist:
        return username
      
    if not self.edit:
      raise forms.ValidationError("Predavatelj s tem uporabniškim imenom že obstaja!")
    else:
      return username

  def clean_pass2(self):
    pass1 = self.cleaned_data.get("pass", "")
    pass2 = self.cleaned_data["pass2"]
    if pass1 != pass2 and not self.edit:
        raise forms.ValidationError("Gesli se ne ujemata.")
    return pass2

  def save(self):
    user = User(
      username = self.cleaned_data['username'],
    )
    if not self.edit: 
      user.set_password(self.cleaned_data['pass'])
      user.save()
      user.groups.add(Group.objects.get(pk = 2))
      user.save()
      UserProfile(
        sifra = self.cleaned_data['sifra'].upper(),
        name = self.cleaned_data['name'].upper(),
        surname = self.cleaned_data['surname'].upper(),
        disabled = self.cleaned_data['disabled'],
        user = user
      ).save()
    else:
      up = UserProfile.objects.get(sifra = self.cleaned_data['sifra'])
      up.name = self.cleaned_data['name'].upper()
      up.surname = self.cleaned_data['surname'].upper()
      up.disabled = self.cleaned_data['disabled']
      up.save()

  @staticmethod
  def search_logic(query, queryset):
    return search.user_profile_search_logic(query, queryset)


class EnrollmentForm(forms.Form):
  """ 
  Form for managing enrollments. 
  """
  
  def __init__(self, *args, **kwargs):
    """
    Class constructor.
    """   
    faculty_year = kwargs.pop('faculty_year', None)
    student = kwargs.pop('student', None)
            
    super(EnrollmentForm, self).__init__(*args, **kwargs)      
    
    self.fields['student_number'] = forms.RegexField(regex = '^[0-9]{8}$', label = u"Vpisna številka", initial = student.student_number if student else None, error_messages = { 'invalid' : u"Vpisna številka mora biti sestavljena iz 8 števk." })  
    self.fields['surname'] = forms.RegexField(regex = '^[^0-9]*$', label = u"Priimek", initial = student.surname if student else None)
    self.fields['maiden_name'] = forms.RegexField(regex = '^[^0-9]*$', label = u"Dekliški priimek", required = False, initial = student.maiden_name if student else None)
    self.fields['first_name'] = forms.RegexField(regex = '^[^0-9]*$', label = u"Ime", initial = student.name if student else None)
    self.fields['identity_num'] = EMSOField(label = u"Enotna matična številka občana", initial = student.identity_num if student else None)
    self.fields['fiscal_num'] = forms.IntegerField(label = u"Davčna številka", initial = student.fiscal_code if student else None)
    
    SPECIAL_NEEDS = (
      ('0', '---------'),
      ('A', u'slepi/slabovidni'),
      ('B', u'gluhi/naglušni'),
      ('C', u'gibalno ovirani/invalidi'),
      ('D', u'drugo')
    )
    self.fields['special_needs'] = forms.ChoiceField(
      SPECIAL_NEEDS,
      required = False,
      label = u"Posebne potrebe", 
      initial = student.special_needs if student else None
    )
    
    self.fields['address'] = forms.CharField(label = u"Ulica in hišna številka", initial = student.address if student else None)
    self.fields['post'] = forms.ModelChoiceField(
      queryset = Post.objects.all().exclude(disabled = True),      
      label = u"Pošta",
      initial = student.post.pk if student else None
    )

    self.fields['region'] = forms.ModelChoiceField(
      queryset = Region.objects.all().exclude(disabled = True),      
      label = u"Občina",
      initial = student.region.pk if student else None
    )
    
    self.fields['country'] = forms.ModelChoiceField(
      queryset = Country.objects.all().exclude(disabled = True),
      initial = student.country.pk if student else Country.objects.get(pk = '705').pk, 
      label = u"Država",
    )    
    
    self.fields['phone_number'] = forms.CharField(label = u"Telefonska številka", initial = student.phone_num if student else None)
    self.fields['mobile_number'] = forms.CharField(label = u"Prenosni telefon", required = False, initial = student.mobile_num if student else None)
    self.fields['email'] = forms.EmailField(label = u"Elektronska pošta", initial = student.email if student else None)    
    
    self.fields['tmp_address'] = forms.CharField(label = u"Ulica in hišna številka (začasna)", required = False, initial = student.tmp_address if student else None)
    self.fields['tmp_post'] = forms.ModelChoiceField(
      queryset = Post.objects.all().exclude(disabled = True),
      required = False,
      label = u"Pošta (začasna)",
      initial = student.tmp_post if student else None
    )

    self.fields['tmp_region'] = forms.ModelChoiceField(
      queryset = Region.objects.all().exclude(disabled = True),      
      required = False,
      label = u"Občina (začasna)",
      initial = student.tmp_region if student else None
    )

    # ----------------------------------------------------------------------------

    self.fields['faculty'] = forms.ModelChoiceField(
      queryset = Faculty.objects.all().exclude(disabled = True),
      initial = Faculty.objects.get(pk = '163').pk,
      label = u"Visokošolski zavod/članica"
    )
    
    self.fields['school_year'] = forms.ModelChoiceField(
      queryset = SchoolYear.objects.all(),
      initial = SchoolYear.objects.latest(),
      label = u"Študijsko leto"
    )
        
    STUDY_TYPES = (
      ('J', u'visokošolski strokovni'),
      ('K', u'univerzitetni'),
      ('L', u'magistrski'),
      ('N', u'enovit magistrski'),
      ('M', u'doktorski'),
      ('B', u'visokošolski strokovni'),
      ('C', u'univerzitetni'),
      ('E', u'specialistični'),
      ('F', u'magistrski'),
      ('G', u'doktorski'),
      ('H', u'enovit doktorski')
    )

    self.fields['study_type'] = forms.ChoiceField(
      STUDY_TYPES,
      required = True,
      label = u"Vrsta študija"
    ) 
        
    STUDY_MODES = (
      ('1', 'redni'), 
      ('2', 'izredni')
    )

    self.fields['study_mode'] = forms.ChoiceField(
      STUDY_MODES,
      required = True,
      label = u"Način študija"
    ) 
    
    DISTANCE_STUDY = (
      ('1','da'),
      ('2','ne')
    )
    
    self.fields['distance_study'] = forms.ChoiceField(
      DISTANCE_STUDY,
      required = True,
      initial = 2,
      label = u"Študij na daljavo"
    )  

    ENROLL_TYPE = (
      ('V1', 'prvi vpis v letnik'),
      ('V2', 'ponavljanje letnika'),
      ('V3', 'nadaljevanje letnika'),
      ('AB', 'absolvent')
    )

    self.fields['enrollment_type'] = forms.ChoiceField(
      ENROLL_TYPE,
      required = True,
      label = u"Vrsta vpisa"
    )
                
    # Define the field with the custom horizontal filter widget
    self.fields['elective_subjects'] = forms.ModelMultipleChoiceField(
      queryset = faculty_year.elective_subjects.all(),
      required = False,
      widget = HorizontalFilterWidget('elective_subjects',title='izbirni predmeti'),
      label = 'Izbirni predmeti'
    )
    
    self.fields['chosen_modules'] = forms.ModelMultipleChoiceField(
      queryset = faculty_year.modules.filter(required = False),
      required = False,      
      widget = HorizontalFilterWidget('chosen_modules',title='izbirni moduli'),
      label = 'Izbirni moduli'
    )      

  def save(self, university_program, study_year):
    student_number = self.cleaned_data['student_number']
    surname = self.cleaned_data['surname']
    maiden_name = self.cleaned_data['maiden_name']
    first_name = self.cleaned_data['first_name']
    identity_num = self.cleaned_data['identity_num']
    special_needs = self.cleaned_data['special_needs']
    address = self.cleaned_data['address']
    post = self.cleaned_data['post']
    region = self.cleaned_data['region']
    country = self.cleaned_data['country']
    phone_number = self.cleaned_data['phone_number']
    mobile_number = self.cleaned_data['mobile_number']
    email = self.cleaned_data['email']
    tmp_address = self.cleaned_data['tmp_address']
    tmp_post = self.cleaned_data['tmp_post']
    tmp_region = self.cleaned_data['tmp_region']
    faculty = self.cleaned_data['faculty']
    #university_program = self.cleaned_data['university_program']
    school_year = self.cleaned_data['school_year']
    study_type = self.cleaned_data['study_type']
    fiscal_code = self.cleaned_data['fiscal_num']
    #study_year = self.cleaned_data['study_year']
    study_mode = self.cleaned_data['study_mode']
    distance_study = self.cleaned_data['distance_study']
    enrollment_type = self.cleaned_data['enrollment_type']
    chosen_modules = self.cleaned_data['chosen_modules']
    elective_subjects = self.cleaned_data['elective_subjects']
    #elective_subjects = [int(subject) for subject in elective_subjects]
    
    if special_needs == '0':
      special_needs = None
      
    if chosen_modules and chosen_modules.count() > 2:
      return u"2|Maksimalno število izbirnih modulov je 2!"      
    
    # Check if user already exists in the system
    try:
      existing_user = User.objects.get(userprofile__student_number=str(student_number))
    except:
      existing_user = None
    
    if existing_user:
      user = existing_user
      
      # If the student enters the same faculty year again, 
      # we delete those exam applications that the user did not pass
      if enrollment_type == "V2":         
        apps = ExamApplication.objects.filter(
          student = existing_user, 
          exam__school_year = existing_user.get_profile().enrollment_forms.filter(
            university_program = university_program
          ).latest().school_year, 
          passed = False
        )

        # Update subject student metadata
        for app in apps:
          StudentSubjectMetadata.add_subtraction(app.student, app.exam.subject)
        
        apps.delete()
        
      # Cannot use "First enrollment" when the student has enrolled to this study year
      if enrollment_type == "V1" and existing_user.get_profile().enrollment_forms.filter(study_year = study_year).count() > 0:
        return u"2|Študent je že vpisan v ta letnik. Izberite ponavljanje letnika ali študenta vpišite v naslednji letnik."
      
      # Check if there is enrollment for this user for the same university program and the same faculty
      if Enrollment.objects.filter(student = existing_user.get_profile(),
                                   university_program = university_program,
                                   faculty = faculty,
                                   school_year = school_year):
        return u"2|Študent s to vpisno številko je že vpisan v ta program na tej fakulteti za to študijsko leto!"      
      
      up = UserProfile(pk = existing_user.get_profile().pk,
        user = user,
        student_number = student_number,
        maiden_name = maiden_name,
        surname = surname,
        name = first_name,
        identity_num = identity_num,
        fiscal_code = fiscal_code,
        special_needs = special_needs,
        address = address,
        post = post,
        region = region,
        country = country,
        phone_num = phone_number,
        mobile_num = mobile_number,
        email = email,
        tmp_address = tmp_address,
        tmp_post = tmp_post,
        tmp_region = tmp_region
      )
    else:
      user = User.objects.create_user(str(student_number), email, '123')
      user.groups = [1]   # user is student
      user.save()
      
      up = UserProfile(
        user = user,
        student_number = student_number,
        maiden_name = maiden_name,
        surname = surname,
        name = first_name,
        identity_num = identity_num,
        fiscal_code = fiscal_code,
        special_needs = special_needs,
        address = address,
        post = post,
        region = region,
        country = country,
        phone_num = phone_number,
        mobile_num = mobile_number,
        email = email,
        tmp_address = tmp_address,
        tmp_post = tmp_post,
        tmp_region = tmp_region
      )            
    
    up.save()
    
    enr = Enrollment(
      student = up, 
      faculty = faculty, 
      university_program = university_program, 
      school_year = school_year, 
      study_type = study_type, 
      study_year = study_year,
      study_mode = study_mode,
      distance_study = distance_study, 
      enrollment_type = enrollment_type
    )
    enr.save()    
            
    obligatory_subjects = Subject.objects.filter(
      faculty_modules__required = True, 
      faculty_modules__faculty_year = study_year
    )
    
    modules_subjects = Subject.objects.filter( 
      faculty_modules__in=chosen_modules
    )
    
    obligatory_modules = FacultyModule.objects.filter(
      required = True,
      faculty_year = study_year
    )            
    
    # Populate student modules and subjects
    for subject in elective_subjects:
      enrsub = EnrollmentSubject(subject = subject, 
        enrollment = enr, 
        module = 'Izbirni predmeti')
      enrsub.save()
      
    for module in obligatory_modules:
      for subject in module.subjects.all():
        enrsub = EnrollmentSubject(subject = subject, 
          enrollment = enr, 
          module = module.name)
        enrsub.save()      
      
    for module in chosen_modules:
      for subject in module.subjects.all():
        enrsub = EnrollmentSubject(subject = subject, 
          enrollment = enr, 
          module = module.name)
        enrsub.save()            
    
    enr.modules.add(*chosen_modules)
        
    up.subjects.add(*elective_subjects)
    up.subjects.add(*obligatory_subjects)
    up.subjects.add(*modules_subjects)
   
class SubjectManageForm(forms.Form):    
  """
  A form for selecting elective subjects for student
  """
  def __init__(self, *args, **kwargs):
    """
    Class constructor.
    """
    elective_subjects = kwargs.pop('elective_subjects', None)
    faculty_year = kwargs.pop('faculty_year', None)
    modules = kwargs.pop('modules', None)
    
    super(SubjectManageForm, self).__init__(*args, **kwargs)

    # Define the field with the custom horizontal filter widget
    self.fields['elective_subjects'] = forms.ModelMultipleChoiceField(
      queryset = faculty_year.elective_subjects.all(),
      initial = [sub.pk for sub in elective_subjects],
      required = False,
      widget = HorizontalFilterWidget('elective_subjects',title='izbirni predmeti'),
      label = 'Izbirni predmeti'
    )
    self.fields['elective_subjects'].top_label = True
    
    self.fields['chosen_modules'] = forms.ModelMultipleChoiceField(
      queryset = faculty_year.modules.filter(required = False),
      initial = [mod.pk for mod in modules],
      required = False,      
      widget = HorizontalFilterWidget('chosen_modules',title='izbirni moduli'),
      label = 'Izbirni moduli'
    )      
    self.fields['chosen_modules'].top_label = True      
        
  def save(self, pre_elective_subjects, student, enr, pre_modules):
    chosen_modules = self.cleaned_data['chosen_modules']
    elective_subjects = self.cleaned_data['elective_subjects']
    
    if chosen_modules and chosen_modules.count() > 2:
      return u"2|Maksimalno število izbirnih modulov je 2!"    
    
    for sub in elective_subjects:
      # we added this subject
      if sub not in pre_elective_subjects:  
        student.subjects.add(sub)
        EnrollmentSubject(subject = sub, enrollment = enr, module = 'Izbirni predmeti').save()        
        
    for sub in pre_elective_subjects:
      # we deleted this subject
      if sub not in elective_subjects:
        student.subjects.remove(sub)
        EnrollmentSubject.objects.filter(subject = sub, enrollment = enr, module = 'Izbirni predmeti').delete()                
        
    for mod in chosen_modules:
      # we added this modules
      if mod not in pre_modules:
        enr.modules.add(mod)
        
        for sub in mod.subjects.all():
          EnrollmentSubject(subject = sub, enrollment = enr, module = mod.name).save()        
        
        student.subjects.add(*mod.subjects.all())
                
    for mod in pre_modules:
      # we deleted this modules
      if mod not in chosen_modules:
        enr.modules.remove(mod)
        
        for sub in mod.subjects.all():
          EnrollmentSubject.objects.filter(subject = sub, enrollment = enr, module = mod.name).delete()        
        
        student.subjects.remove(*mod.subjects.all())
                
